`include "defines.d"
module arbiter(
	// inputs
	clock, reset,
	req_e, req_s, req_w, req_n, req_h,			// input requests from each iqueue
	type_e, type_s, type_w, type_n, type_h,	// tags from each iqueue
	ready_in,											// ready in from the outuput port associated with this arbiter
	// outputs
	grant_e, grant_s, grant_w, grant_n, grant_h	// one-hot grant 
);

	input wire clock, reset, req_e, req_s, req_w, req_n, req_h;
	input wire [1:0] type_e, type_s, type_w, type_n, type_h;
	input wire ready_in;
	
	output wire grant_e, grant_s, grant_w, grant_n, grant_h;
	
	wire [4:0] req_bus = {req_h,req_n,req_w,req_s,req_e};
	wire [4:0] grant_bus;
	
	wire granted_input_is_tail;
	assign granted_input_is_tail = (grant_bus == 5'b00001) ? (type_e == `TAIL) :
											 (grant_bus == 5'b00010) ? (type_s == `TAIL) :
											 (grant_bus == 5'b00100) ? (type_w == `TAIL) :
											 (grant_bus == 5'b01000) ? (type_n == `TAIL) :
											 (grant_bus == 5'b10000) ? (type_h == `TAIL) :
											 0;

	wire update_enable = granted_input_is_tail & ready_in;
	
	reg [4:0] 	priority;
	wire [4:0] carry, sub_carry, next_priority;
	
	always @(posedge clock or negedge reset) begin
		if(!reset) priority <= 5'b00001;
		else begin
			priority <= (!update_enable) ? priority : 
							(grant_bus == 5'b00001) ? 5'b00010 :
							(grant_bus == 5'b00010) ? 5'b00100 :
							(grant_bus == 5'b00100) ? 5'b01000 :
							(grant_bus == 5'b01000) ? 5'b10000 :
							(grant_bus == 5'b10000) ? 5'b00001 :
							5'b00001;
		end
	end
	
	assign sub_carry = priority | carry;
	assign grant_bus = req_bus & sub_carry;
	
	assign carry[0] = ~req_bus[4] & sub_carry[4]; // potential loop
	assign carry[1] = ~req_bus[0] & sub_carry[0];
	assign carry[2] = ~req_bus[1] & sub_carry[1];
	assign carry[3] = ~req_bus[2] & sub_carry[2];
	assign carry[4] = ~req_bus[3] & sub_carry[3];
	
	// final outputs
	assign grant_e = grant_bus[0];
	assign grant_s = grant_bus[1];
	assign grant_w = grant_bus[2];
	assign grant_n = grant_bus[3];
	assign grant_h = grant_bus[4];


endmodule
